package com.aspire.aimini.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.aspire.aimini.constant.CommonConstant;
import com.aspire.aimini.exception.BusinessException;
import com.aspire.aimini.model.dto.UserDTO;
import com.aspire.aimini.model.entity.User;
import com.aspire.aimini.model.query.UserQuery;
import com.aspire.aimini.repository.UserRepository;
import com.aspire.aimini.service.UserService;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author wangguiyou
 * @date 2024-12-19
 * @description 用户业务逻辑实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserRepository, User> implements UserService {

    private final UserRepository userRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(UserDTO userDTO) {
        // 检查用户名是否已存在
        if (isUsernameExists(userDTO.getUsername(), null)) {
            throw new BusinessException("用户名已存在");
        }

        // 检查邮箱是否已存在
        if (StrUtil.isNotBlank(userDTO.getEmail()) && isEmailExists(userDTO.getEmail(), null)) {
            throw new BusinessException("邮箱已存在");
        }

        // 检查手机号是否已存在
        if (StrUtil.isNotBlank(userDTO.getPhone()) && isPhoneExists(userDTO.getPhone(), null)) {
            throw new BusinessException("手机号已存在");
        }

        // 创建用户实体
        User user = BeanUtil.copyProperties(userDTO, User.class);
        user.setPassword(BCrypt.hashpw(userDTO.getPassword(), BCrypt.gensalt()));
        user.setRole(StrUtil.isBlank(userDTO.getRole()) ? CommonConstant.ROLE_USER : userDTO.getRole());
        user.setStatus(CommonConstant.STATUS_ENABLED);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());

        return save(user);
    }

    @Override
    public String login(String username, String password, String loginIp) {
        // 查询用户
        User user = findByUsername(username);
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }

        // 检查用户状态
        if (!CommonConstant.STATUS_ENABLED.equals(user.getStatus())) {
            throw new BusinessException("用户已被禁用");
        }

        // 验证密码
        if (!BCrypt.checkpw(password, user.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }

        // 更新最后登录信息
        userRepository.updateLastLoginInfo(user.getId(), LocalDateTime.now(), loginIp);

        // Sa-Token登录
        StpUtil.login(user.getId());
        return StpUtil.getTokenValue();
    }

    @Override
    public User findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public User findByEmail(String email) {
        return userRepository.findByEmail(email);
    }

    @Override
    public User findByPhone(String phone) {
        return userRepository.findByPhone(phone);
    }

    @Override
    public IPage<UserDTO> pageUsers(UserQuery query) {
        Page<User> page = new Page<>(query.getPageNum(), query.getPageSize());

        IPage<User> userPage = userRepository.selectUserPage(
                page,
                query.getUsername(),
                query.getNickname(),
                query.getEmail(),
                query.getPhone(),
                query.getRole(),
                query.getStatus(),
                query.getCreateTimeStart(),
                query.getCreateTimeEnd());

        // 转换为DTO
        IPage<UserDTO> dtoPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        List<UserDTO> dtoList = userPage.getRecords().stream()
                .map(user -> {
                    UserDTO dto = BeanUtil.copyProperties(user, UserDTO.class);
                    dto.setPassword(null); // 不返回密码
                    return dto;
                })
                .collect(Collectors.toList());
        dtoPage.setRecords(dtoList);

        return dtoPage;
    }

    @Override
    public UserDTO getUserById(Long id) {
        User user = getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        UserDTO dto = BeanUtil.copyProperties(user, UserDTO.class);
        dto.setPassword(null); // 不返回密码
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createUser(UserDTO userDTO) {
        return register(userDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUser(Long id, UserDTO userDTO) {
        User existingUser = getById(id);
        if (existingUser == null) {
            throw new BusinessException("用户不存在");
        }

        // 检查用户名是否已存在（排除当前用户）
        if (StrUtil.isNotBlank(userDTO.getUsername()) && isUsernameExists(userDTO.getUsername(), id)) {
            throw new BusinessException("用户名已存在");
        }

        // 检查邮箱是否已存在（排除当前用户）
        if (StrUtil.isNotBlank(userDTO.getEmail()) && isEmailExists(userDTO.getEmail(), id)) {
            throw new BusinessException("邮箱已存在");
        }

        // 检查手机号是否已存在（排除当前用户）
        if (StrUtil.isNotBlank(userDTO.getPhone()) && isPhoneExists(userDTO.getPhone(), id)) {
            throw new BusinessException("手机号已存在");
        }

        // 更新用户信息
        User user = BeanUtil.copyProperties(userDTO, User.class);
        user.setId(id);
        user.setPassword(null); // 不更新密码
        user.setUpdateTime(LocalDateTime.now());

        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteUser(Long id) {
        User user = getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 不能删除管理员用户
        if (CommonConstant.ROLE_ADMIN.equals(user.getRole())) {
            throw new BusinessException("不能删除管理员用户");
        }

        return removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteUsers(List<Long> ids) {
        // 检查是否包含管理员用户
        List<User> users = listByIds(ids);
        boolean hasAdmin = users.stream().anyMatch(user -> CommonConstant.ROLE_ADMIN.equals(user.getRole()));
        if (hasAdmin) {
            throw new BusinessException("不能删除管理员用户");
        }

        return removeByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUserStatus(Long id, Integer status) {
        User user = getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 不能禁用管理员用户
        if (CommonConstant.ROLE_ADMIN.equals(user.getRole()) && CommonConstant.STATUS_DISABLED.equals(status)) {
            throw new BusinessException("不能禁用管理员用户");
        }

        user.setStatus(status);
        user.setUpdateTime(LocalDateTime.now());
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchUpdateUserStatus(List<Long> ids, Integer status) {
        // 如果是禁用操作，检查是否包含管理员用户
        if (CommonConstant.STATUS_DISABLED.equals(status)) {
            List<User> users = listByIds(ids);
            boolean hasAdmin = users.stream().anyMatch(user -> CommonConstant.ROLE_ADMIN.equals(user.getRole()));
            if (hasAdmin) {
                throw new BusinessException("不能禁用管理员用户");
            }
        }

        return userRepository.batchUpdateStatus(ids, status) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean resetPassword(Long id, String newPassword) {
        User user = getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        user.setUpdateTime(LocalDateTime.now());
        return updateById(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changePassword(Long id, String oldPassword, String newPassword) {
        User user = getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        // 验证旧密码
        if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
            throw new BusinessException("原密码错误");
        }

        user.setPassword(BCrypt.hashpw(newPassword, BCrypt.gensalt()));
        user.setUpdateTime(LocalDateTime.now());
        return updateById(user);
    }

    @Override
    public boolean isUsernameExists(String username, Long excludeId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        if (excludeId != null) {
            wrapper.ne(User::getId, excludeId);
        }
        return count(wrapper) > 0;
    }

    @Override
    public boolean isEmailExists(String email, Long excludeId) {
        if (StrUtil.isBlank(email)) {
            return false;
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        if (excludeId != null) {
            wrapper.ne(User::getId, excludeId);
        }
        return count(wrapper) > 0;
    }

    @Override
    public boolean isPhoneExists(String phone, Long excludeId) {
        if (StrUtil.isBlank(phone)) {
            return false;
        }
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPhone, phone);
        if (excludeId != null) {
            wrapper.ne(User::getId, excludeId);
        }
        return count(wrapper) > 0;
    }

    @Override
    public UserStatistics getUserStatistics() {
        Long totalUsers = userRepository.countUsers(null);
        Long activeUsers = userRepository.countUsers(CommonConstant.STATUS_ENABLED);
        Long inactiveUsers = userRepository.countUsers(CommonConstant.STATUS_DISABLED);

        LambdaQueryWrapper<User> adminWrapper = new LambdaQueryWrapper<>();
        adminWrapper.eq(User::getRole, CommonConstant.ROLE_ADMIN);
        Long adminUsers = count(adminWrapper);

        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(User::getRole, CommonConstant.ROLE_USER);
        Long normalUsers = count(userWrapper);

        return new UserStatistics(totalUsers, activeUsers, inactiveUsers, adminUsers, normalUsers);
    }
}